<!--
 * @Description: 滚动区域  vue2 写法
 * @Author bianpengfei
 * @create 2021/12/27 20:58
 -->
<template>
  <div
    :style="_style"
    class="scroll-view__wrapper"
  >
    <div
      ref="scrollViewRef"
      :class="[
        'scroll-view div--webkit--scrollbar scroll-view__inner',
        !showScrollBar && 'scroll-view--scrollbar-none',
        uniqueClassName,
        innerScrollViewClass
      ]"
    >
      <slot />
      <el-backtop
        v-if="showBackTop"
        :target="`.${uniqueClassName}`"
      />
    </div>
  </div>
</template>

<script>
import { uuid as uniqueKey, scrollToElement, isString, observerElementMutation, debounce } from 'sf-utils2'
import { position } from './position'

const { routePosition } = position

export default {
  name: 'ScrollView',
  props: {
    height: {
      type: String,
      default: ''
      // require: true
    },
    showScrollBar: {
      // 是否展示滚动条
      type: Boolean,
      default: true
    },
    enabledScrollListener: {
      // 是否开启滚动监听
      type: Boolean,
      default: false
    },

    showBackTop: {
      // 是否显示 backTop
      type: Boolean,
      default: true
    },

    // 内部滚动class
    innerScrollViewClass: {
      type: String,
      default: ``
    }
  },
  emits: [`on-scroll`, 'on-scroll-to-bottom'],

  data() {
    return {
      uniqueClassName: '',
      innerHeight: ''
    }
  },

  computed: {
    _style() {
      const height = this.innerHeight || this.height
      const unit = String(height).replace(/\d+\.?/g, '') || 'px'
      return {
        height: /^calc/.test(height) ? height : parseFloat(height) + unit
      }
    }
  },

  activated() {
    const scrollTop = routePosition[this._key]?.y

    if (scrollTop) {
      this.setScrollTop(scrollTop)
    }
  },

  deactivated() {
    routePosition[this._key] = {
      x: 0,
      y: this.$refs.scrollViewRef?.scrollTop
    }
  },

  created() {
    const uniqueKeyTemp = 'x' + uniqueKey()
    this._key = `_${uniqueKey()}@${uniqueKeyTemp}_${Number(new Date()).toString()}`
    this.uniqueClassName = uniqueKeyTemp
  },

  mounted() {
    this.throttledScrollHandler = this.onScroll
    this.debounceScrollHandler = debounce(this.onScrollToBottom.bind(this), 300)
    this.debounceWinResize = debounce(this.winResize.bind(this), 400)
    this.$refs.scrollViewRef.addEventListener('scroll', this.throttledScrollHandler)

    if (!this.height || this.height == '100%') {
      const target = this.$el.parentElement || document.body
      this._observerMuation = observerElementMutation({
        callback: () => {
          this.innerHeight = target.clientHeight
        },
        options: { el: this.$el.parentElement || document.body }
      })
      this._observerMuation.start()
      this.innerHeight = target.clientHeight
    }
    window.addEventListener('resize', this.debounceWinResize, false)
  },

  beforeUnmount() {
    window.removeEventListener('resize', this.debounceWinResize, false)
    this.$refs.scrollViewRef && this.$refs.scrollViewRef.removeEventListener('scroll', this.throttledScrollHandler)
  },

  methods: {
    /**
     * 窗口变化
     */
    winResize() {
      if (!this.height || this.height == '100%') {
        const target = this.$el.parentElement || document.body
        this.innerHeight = target.clientHeight
      }
    },

    /**
     * 滚动
     * @param event
     */
    onScroll(event) {
      if (!this.enabledScrollListener) return
      const scrollTop = this.$refs.scrollViewRef.scrollTop
      const windowHeight = this.$refs.scrollViewRef.clientHeight
      const scrollHeight = this.$refs.scrollViewRef.scrollHeight
      this.$emit('on-scroll', scrollTop, event)
      console.log('scrollTop', scrollTop)
      this.debounceScrollHandler(scrollTop, windowHeight, scrollHeight, event)
    },

    /**
     * 获取滚动区域节点
     * @expose
     */
    getScrollView() {
      return this.$refs.scrollViewRef
    },

    /**
     * 监听是否滚动到底部
     * @param scrollTop
     * @param windowHeight
     * @param scrollHeight
     */
    onScrollToBottom(scrollTop, windowHeight, scrollHeight) {
      if (!this.enabledScrollListener) return
      console.log('滚动', scrollTop)
      /* fix 重新请求导致底部重新加载问题 */
      if (scrollTop && scrollHeight - scrollTop - windowHeight <= 50) {
        console.log('发生变化，滚动条')
        this.$emit('on-scroll-to-bottom', arguments[3])
      }
    },

    /**
     * @expose
     * @param val
     */
    setScrollTop(val) {
      console.log(val)
      this.$nextTick(() => {
        this.$refs.scrollViewRef.scrollTop = val
      })
    },

    /**
     * 滚动到指定元素
     * @param {Element|String} stor
     * @param {Function} cb
     */
    scrollToElement(stor = '', cb) {
      const scrollElement = this.$refs.scrollViewRef
      const targetDom = isString(stor) ? this.$el.querySelector(stor) : stor
      scrollToElement({ target: targetDom, scrollElement, cb })
    }
  }
}
</script>

<style scoped lang="less">
.scroll-view__wrapper {
  display: flex;
  flex-direction: column;
  .scroll-view {
    flex: 1;
    width: 100%;
    over-flow: auto; /* winphone8和android4+ */
    -webkit-overflow-scrolling: touch; /* ios5+ */
    overflow: auto;
    .ios-bounce-android;
    .div--webkit--scrollbar();
    //scroll-behavior: smooth;
    &.scroll-view--scrollbar-none {
      &::-webkit-scrollbar {
        width: 0;
        height: 0;
        display: none;
        color: transparent;
      }
    }
  }
}
</style>
